#ifndef ___fat32_subtransaccion14_crear_entrada_para_archivo

#define ___fat32_subtransaccion14_crear_entrada_para_archivo 1

#include "f32_mto.c"

#include "f32_opAL.c"
#include "f32_opAM.c"
#include "f32_opAT.c"
#include "f32_opAX.c"
#include "f32_opAY.c"
#include "f32_opAZ.c"
#include "f32_opBA.c"

struct fat32st14_resultado {
  fat32_lista_bloques_para_escribir * lbpe;
  unsigned long numeroBloque;
  unsigned short posicionBloque;
};

struct fat32st14_datos {
  char * nombreArchivo;
  unsigned char soloLectura;
  unsigned long clusterInicial;
  unsigned int conexion;
  unsigned char resultado;
  char * directorio;
  unsigned long tamanoActualDirectorio;
  unsigned long * cadena;
  unsigned long * sectores;
  unsigned long numeroBloque;
  unsigned short offsetBloque;
  char bloque[2048];
  unsigned long posicionActual;
  char * entradasDir;
  unsigned char cantEntradasDir;
  char nombreCorto[11];
  unsigned char nombresCoinciden;
  unsigned long entradasDisponibles;
  unsigned long posicionEntradaDir;
  unsigned long * nuevosClusteres;
  unsigned char cantidadSolicitados;
  fat32_lista_bloques_para_escribir * escriturasNecesarias;
  struct fat32st14_resultado * resultado;
};

unsigned char fat32st_crear_entrada_para_archivo(unsigned char, unsigned int, char *, unsigned char, unsigned long, void **, unsigned char, 
                                                                                                                                    void *);

unsigned char fat32st_crear_entrada_para_archivo (unsigned char estado, unsigned int transaccion, char * nombreArchivo, 
                                                  unsigned char soloLectura, unsigned long clusterInicialDir, void ** datos,
                                                  unsigned char estadoOp, void * datosOp) {
  struct fat32st14_datos datosST = *datos;
  switch (estado) {
  case 0:
    datosST = malloc(sizeof(struct fat32st14_datos));
    *datos = datosST;
    datosST -> nombreArchivo = nombreArchivo;
    datosST -> soloLectura = soloLectura;
    datosST -> clusterInicial = clusterInicialDir;
    datosST -> conexion = fat32_obtener_conexion_para_transaccion(transaccion);
    datosST -> directorio = NULL;
    datosST -> tamanoActualDirectorio = 0;
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_clusteres, &(datosST -> clusterInicial), sizeof (datosST -> clusterInicial));
    return 1;
  case 1:
    datosST -> cadena = datosOp;
    fat32_quitar_operacion(transaccion);
    unsigned long longCadena;
    for (longCadena = 0; (datosST -> cadena)[longCadena]; longCadena ++);
    longCadena ++;
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_sectores_desde_clusteres, &(datosST -> cadena),
                                                                       sizeof(unsigned long int) * longCadena);
    return 2;
  case 2:
    datosST -> sectores = datosOp;
    fat32_quitar_operacion(transaccion);
    unsigned int cantidadSectoresEnDir;
    for (cantidadSectoresEnDir = 0; (datosST -> sectores)[cantidadSectoresEnDir]; cantidadSectoresEnDir ++);
    datosST -> tamanoActualDirectorio = cantidadSectoresEnDir;
    datosST -> posicionActual = 0;
    datosST -> numeroBloque = 0;
    return 3;
  case 3:
    if (!(datosST -> sectores)[datosST -> posicionActual]) return 6;
    unsigned long numeroSector = (datosST -> sectores)[datosST -> posicionActual];
    datosST -> offsetBloque = (numeroSector & 3) * 512;
    numeroSector &= ~3L;
    if (numeroSector == (datosST -> numeroBloque)) return 5;
    datosST -> numeroBloque = numeroSector;
    struct fat32opAM_solicitud_bloque ds;
    ds.conexion = datosST -> conexion;
    ds.sector = datosST -> numeroBloque;
    ds.buffer = datosST -> bloque;
    fat32_crear_operacion(transaccion, &fat32op_solicitar_bloque, &ds, sizeof ds);
    return 4;
  case 4:
    fat32_quitar_operacion(transaccion);
    return 5;
  case 5:
    datosST -> directorio = fb_cambiar_tamano(datosST -> directorio, 512, 1 + datosST -> tamanoActualDirectorio);
    memcpy((datosST -> directorio) + 512 * (datosST -> tamanoActualDirectorio), (datosST -> bloque) + (datosST -> offsetBloque), 512);
    (datosST -> tamanoActualDirectorio) ++;
    (datosST -> posicionActual) ++;
    return 3;
  case 6:
    46;
    struct fat32opAY_datos_conversion dcn;
    dcn.nombreLargo = datosST -> nombreArchivo;
    dcn.directorio = datosST -> directorio;
    dcn.cantidadSectores = datosST -> tamanoActualDirectorio;
    dcn.bufferSalida = datosST -> nombreCorto;
    fat32_crear_operacion(transaccion, &fat32op_generar_nombre_corto_desde_nombre_largo, &dcn, sizeof dcn);
    return 7;
  case 7:
    fat32_quitar_operacion(transaccion);
    datosST -> nombresCoinciden = estadoOp - 1;
    return 8;
  case 8:
    46;
    struct fat32opAX_datos_creacion_entrada de;
    de.nombreLargo = (datosST -> nombresCoinciden) ? NULL : (datosST -> nombreArchivo);
    de.soloLectura = datosST -> soloLectura;
    ds.nombreCorto = datosST -> nombreCorto;
    fat32_crear_operacion(transaccion, &fat32op_generar_entradas_para_archivo, &de, sizeof de);
    return 9;
  case 9:
    datosST -> cantEntradasDir = estadoOp;
    datosST -> entradasDir = datosOp;
    fat32_quitar_operacion(transaccion);
    struct fat32opAZ_datos_busqueda dbe;
    dbe.directorio = datosST -> directorio;
    dbe.cantEntradas = datosST -> tamanoActualDirectorio * 16;
    dbe.entradasSolicitadas = datosST -> cantEntradasDir;
    fat32_crear_operacion(transaccion, &fat32op_buscar_posicion_para_entradas_directorio, &dbe, sizeof dbe);
    return 10;
  case 10:
    46;
    unsigned long resultadoE = *((unsigned long *) datosOp);
    free(datosOp);
    fat32_quitar_operacion(transaccion);
    datosST -> cantidadSolicitados = 0;
    if (estadoOp == 1) {
      datosST -> posicionEntradaDir = resultadoE;
      return 15;
    } else {
      datosST -> entradasDisponibles = resultadoE;
      return 11;
    }
  case 11:
    46;
    unsigned long ultimoClusterCadena;
    unsigned long posicionUltimo;
    for (posicionUltimo = 0; (datosST -> cadena)[posicionUltimo + 1]; posicionUltimo ++);
    ultimoClusterCadena = (datosST -> cadena)[posicionUltimo];
    struct fat32opBA_datos_solicitud dsc;
    dsc.ultimoClusterActual = ultimoClusterCadena;
    datosST -> cantidadSolicitados = (((datosST -> cantEntradasDir) - (datosST -> entradasDisponibles)) > 16) ? 2 : 1;
    dsc.cantidad = datosST -> cantidadSolicitados;
    fat32_crear_transaccion(transaccion, &fat32op_obtener_clusteres_adicionales, &dsc, sizeof dsc);
    return 12;
  case 12:
    if (estadoOp == 1) datosST -> nuevosClusteres = datosOp;
    fat32_quitar_transaccion(transaccion);
    if (estadoOp == 2) return 16;
    datosST -> posicionEntradaDir = (datosST -> tamanoActualDirectorio) * 16 - (datosST -> entradasDisponibles);
    return 13;
  case 13:
    datosST -> cadena = fb_cambiar_tamano(datosST -> cadena, sizeof(unsigned long),
                                ((datosST -> tamanoActualDirectorio) / (bootsector.sectoresPorCluster) + 1 + (datosST -> cantidadSolicitados);
    (datosST -> cadena)[(datosST -> tamanoActualDirectorio) / bootsector.sectoresPorCluster] = *(datosST -> nuevosClusteres);
    if ((datosST -> cantidadSolicitados) == 2)
      (datosST -> cadena)[((datosST -> tamanoActualDirectorio) / bootsector.sectoresPorCluster) + 1] = (datosST -> nuevosClusteres)[1];
    (datosST -> cadena)[((datosST -> tamanoActualDirectorio) / bootsector.sectoresPorCluster) + (datosST -> cantidadSolicitados)] = 0;
    free(datosST -> nuevosClusteres);
    datosST -> tamanoActualDirectorio += (datosST -> cantidadSolicitados) * bootsector.sectoresPorCluster;
    fat32_crear_operacion(transaccion, &fat32op_obtener_cadena_sectores_desde_clusteres, &(datosST -> cadena),
                          (((datosST -> tamanoActualDirectorio) / bootsector.sectoresPorCluster) + 1) * sizeof(unsigned long));
    return 14;
  case 14:
    free(datosST -> sectores);
    datosST -> sectores = datosOp;
    fat32_quitar_operacion(transaccion);
    return 15;
  case 15:
    datosST -> escriturasNecesarias = malloc(sizeof(fat32_lista_bloques_para_escribir));
    fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_CREAR, &(datosST -> escriturasNecesarias), 0, 0, 0, NULL);
    unsigned long posicionActual;
    if (datosST -> cantidadSolicitados) {
      char datosNulos[512];
      for (posicionActual = 0; posicionActual < 512; posicionActual ++) datosNulos[posicionActual] = 0;
      posicionActual = datosST -> tamanoActualDirectorio;
      posicionActual -= bootsector.sectoresPorCluster * (datosST -> cantidadSolicitados);
      for (; posicionActual < (datosST -> tamanoActualDirectorio); posicionActual ++)
        fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, &(datosST -> escriturasNecesarias),
                                                       ((datosST -> sectores)[posicionActual]) & ~3L,
                                                       (((datosST -> sectores)[posicionActual]) & 3) * 512, 512, datosNulos);
    }
    unsigned long numeroEntrada;
    unsigned long numeroBloque;
    unsigned long posicionBloque;
    numeroEntrada = datosST -> posicionEntradaDir;
    for (posicionActual = datosST -> cantEntradasDir; posicionActual; posicionActual --, numeroEntrada ++) {
      numeroBloque = (datosST -> sectores)[numeroEntrada / 16];
      posicionBloque = 512 * (numeroBloque & 3);
      numeroBloque &= ~3L;
      posicionBloque += 32 * (numeroEntrada % 16);
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, &(datosST -> escriturasNecesarias), numeroBloque, posicionBloque,
                                                                                          32, (datosST -> entradasDir)[posicionActual - 1]);
    }
    return 17;
  case 16:
    datosST -> escriturasNecesarias = NULL;
    return 17;
  case 17:
    datosST -> resultado = malloc(sizeof(struct fat32st14_resultado));
    (datosST -> resultado) -> lbpe = datosST -> escriturasNecesarias;
    unsigned long posFinal = (datosST -> posicionEntradaDir) + (datosST -> cantidadEntradasDir) - 1;
    (datosST -> resultado) -> numeroBloque = (datosST -> sectores)[posFinal / 16];
    (datosST -> resultado) -> posicionBloque = 512 * (((datosST -> resultado) -> numeroBloque) & 3);
    (datosST -> resultado) -> numeroBloque &= ~3L;
    (datosST -> resultado) -> posicionBloque += posFinal % 16;
    free(datosST -> cadena);
    free(datosST -> sectores);
    free(datosST -> directorio);
    free(datosST -> entradasDir);
    *datos = datosST -> resultado;
    free(datosST);
    return 0;
  }
}

#endif